using Microsoft.EntityFrameworkCore;
using TerritoryGame.Domain.Entities;
using TerritoryGame.Domain.ValueObjects;

namespace TerritoryGame.Infrastructure.Data;

public class TerritoryGameDbContext : DbContext
{
    public TerritoryGameDbContext(DbContextOptions<TerritoryGameDbContext> options) : base(options)
    {
    }

    public DbSet<Game> Games { get; set; }
    public DbSet<Player> Players { get; set; }
    public DbSet<Canvas> Canvases { get; set; }
    public DbSet<GameHistory> GameHistories { get; set; }
    public DbSet<GameHistoryPlayer> GameHistoryPlayers { get; set; }
    public DbSet<User> Users { get; set; }

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        base.OnModelCreating(modelBuilder);

        // Game entity configuration
        modelBuilder.Entity<Game>(entity =>
        {
            entity.HasKey(e => e.Id);
            entity.Property(e => e.Id).HasConversion(
                id => id.Value,
                value => new GameId(value));
            
            entity.Property(e => e.Name).HasConversion(
                name => name.Value,
                value => new GameName(value));
            
            entity.Property(e => e.Duration).HasConversion(
                duration => duration.Value,
                value => new GameDuration(value));
            
            entity.Property(e => e.Status).HasConversion<string>();
            
            entity.HasOne(e => e.Canvas)
                .WithOne()
                .HasForeignKey<Canvas>("GameId");
        });

        // Player entity configuration
        modelBuilder.Entity<Player>(entity =>
        {
            entity.HasKey(e => e.Id);
            entity.Property(e => e.Id).HasConversion(
                id => id.Value,
                value => new PlayerId(value));
            
            entity.Property(e => e.Nickname).HasConversion(
                nickname => nickname.Value,
                value => new PlayerNickname(value));
            
            entity.Property(e => e.Color).HasConversion(
                color => color.Value,
                value => new PlayerColor(value));
            
            entity.HasOne<Game>()
                .WithMany(g => g.Players)
                .HasForeignKey("GameId");
        });

        // Canvas entity configuration
        modelBuilder.Entity<Canvas>(entity =>
        {
            entity.HasKey(e => e.Id);
            entity.Property(e => e.Id).HasConversion(
                id => id.Value,
                value => new CanvasId(value));
            
            // Store painted pixels as JSON
            entity.Property(e => e.PaintedPixelsData)
                .HasConversion(
                    pixels => System.Text.Json.JsonSerializer.Serialize(pixels, (System.Text.Json.JsonSerializerOptions?)null),
                    json => System.Text.Json.JsonSerializer.Deserialize<Dictionary<Position, PlayerColor>>(json, (System.Text.Json.JsonSerializerOptions?)null) ?? new Dictionary<Position, PlayerColor>())
                .Metadata.SetValueComparer(new Microsoft.EntityFrameworkCore.ChangeTracking.ValueComparer<Dictionary<Position, PlayerColor>>(
                    (c1, c2) => c1.Count == c2.Count && !c1.Except(c2).Any(),
                    c => c.Aggregate(0, (a, v) => HashCode.Combine(a, v.GetHashCode())),
                    c => new Dictionary<Position, PlayerColor>(c)));
        });

        // GameHistory entity configuration
        modelBuilder.Entity<GameHistory>(entity =>
        {
            entity.HasKey(e => e.Id);
            entity.Property(e => e.RoomCode).IsRequired();
            entity.Property(e => e.RoomName).IsRequired();
            
            // 暂时注释掉唯一索引，避免迁移冲突
            // entity.HasIndex(e => e.RoomCode).IsUnique();
            
            entity.HasMany(e => e.Players)
                  .WithOne()
                  .HasForeignKey(p => p.GameHistoryId);
        });

        modelBuilder.Entity<GameHistoryPlayer>(entity =>
        {
            entity.HasKey(e => e.Id);
            entity.Property(e => e.PlayerId).IsRequired();
            entity.Property(e => e.Nickname).IsRequired();
            entity.Property(e => e.Color).IsRequired();
            entity.HasIndex(e => e.UserId);
        });

        modelBuilder.Entity<User>(entity =>
        {
            entity.HasKey(e => e.Id);
            entity.HasIndex(e => e.Username).IsUnique();
            entity.HasIndex(e => e.Email).IsUnique();
            entity.Property(e => e.Username).IsRequired();
            entity.Property(e => e.Email).IsRequired();
            entity.Property(e => e.PasswordHash).IsRequired();
        });

        // Position value object configuration
        modelBuilder.Entity<Position>(entity =>
        {
            entity.HasKey(e => new { e.X, e.Y });
            entity.Property(e => e.X);
            entity.Property(e => e.Y);
        });
    }
}
